package com.example.libary.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.libary.common.ResultCode;
import com.example.libary.dto.BorrowRecordDTO;
import com.example.libary.entity.Book;
import com.example.libary.entity.BorrowRecord;
import com.example.libary.exception.BusinessException;
import com.example.libary.mapper.BorrowRecordMapper;
import com.example.libary.service.BookService;
import com.example.libary.service.BorrowRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 借阅记录服务实现类
 */
@Service
@RequiredArgsConstructor
public class BorrowRecordServiceImpl extends ServiceImpl<BorrowRecordMapper, BorrowRecord> implements BorrowRecordService {

    private final BookService bookService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean borrow(Long userId, Long bookId, Integer days) {
        // 检查图书是否可借
        if (!checkBookAvailable(bookId)) {
            throw new BusinessException(ResultCode.BOOK_BORROWED);
        }

        // 检查用户借阅数量是否超过限制
        int borrowCount = countBorrowingByUserId(userId);
        if (borrowCount >= 5) {
            throw new BusinessException(ResultCode.BORROW_LIMIT);
        }

        // 创建借阅记录
        BorrowRecord record = new BorrowRecord();
        record.setUserId(userId);
        record.setBookId(bookId);
        record.setBorrowDate(LocalDateTime.now());
        record.setDueDate(LocalDateTime.now().plusDays(days));
        record.setStatus("0"); // 借阅中
        record.setRenewCount(0); // 续借次数

        // 更新图书可借数量
        Book book = bookService.getById(bookId);
        boolean updateResult = bookService.updateAvailable(bookId, book.getAvailable() - 1);
        if (!updateResult) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "更新图书可借数量失败");
        }

        // 保存借阅记录
        return save(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean returnBook(Long id) {
        // 查询借阅记录
        BorrowRecord record = getById(id);
        if (record == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "借阅记录不存在");
        }

        // 检查是否已归还
        if ("1".equals(record.getStatus())) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "图书已归还");
        }

        // 更新借阅记录
        record.setStatus("1"); // 已归还
        record.setReturnDate(LocalDateTime.now());

        // 计算罚款
        if (LocalDateTime.now().isAfter(record.getDueDate())) {
            // 超期天数
            long days = java.time.Duration.between(record.getDueDate(), LocalDateTime.now()).toDays();
            // 每天罚款0.5元
            record.setFine(record.getFine() != null ? record.getFine().add(new java.math.BigDecimal("0.5").multiply(new java.math.BigDecimal(days))) : new java.math.BigDecimal("0.5").multiply(new java.math.BigDecimal(days)));
        }

        // 更新图书可借数量
        Book book = bookService.getById(record.getBookId());
        boolean updateResult = bookService.updateAvailable(record.getBookId(), book.getAvailable() + 1);
        if (!updateResult) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "更新图书可借数量失败");
        }

        // 更新借阅记录
        return updateById(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean renew(Long id, Integer days) {
        // 查询借阅记录
        BorrowRecord record = getById(id);
        if (record == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "借阅记录不存在");
        }

        // 检查是否已归还
        if ("1".equals(record.getStatus())) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "图书已归还，无法续借");
        }

        // 检查续借次数是否超过限制
        if (record.getRenewCount() >= 2) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "续借次数已达上限");
        }

        // 更新借阅记录
        record.setDueDate(record.getDueDate().plusDays(days));
        record.setRenewCount(record.getRenewCount() + 1);

        // 更新借阅记录
        return updateById(record);
    }

    @Override
    public Page<BorrowRecord> page(Page<BorrowRecord> page, Long userId, Long bookId, String status) {
        LambdaQueryWrapper<BorrowRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(userId != null, BorrowRecord::getUserId, userId)
                .eq(bookId != null, BorrowRecord::getBookId, bookId)
                .eq(status != null, BorrowRecord::getStatus, status)
                .orderByDesc(BorrowRecord::getCreateTime);
        return page(page, wrapper);
    }

    @Override
    public Page<BorrowRecordDTO> pageWithDetails(Page<BorrowRecordDTO> page, Long userId, Long bookId, String status) {
        LambdaQueryWrapper<BorrowRecord> wrapper = new LambdaQueryWrapper<>();
        
        wrapper.eq(userId != null, BorrowRecord::getUserId, userId)
                .eq(bookId != null, BorrowRecord::getBookId, bookId);
        
        // 状态转换：前端字符串 -> 数据库数字
        if (status != null) {
            String dbStatus;
            switch (status) {
                case "BORROWED":
                    dbStatus = "0";
                    break;
                case "RETURNED":
                    dbStatus = "1";
                    break;
                case "OVERDUE":
                    dbStatus = "2";
                    break;
                default:
                    dbStatus = status;
                    break;
            }
            wrapper.eq(BorrowRecord::getStatus, dbStatus);
        }
        
        return baseMapper.selectPageWithDetails(page, wrapper);
    }

    @Override
    public int countBorrowingByUserId(Long userId) {
        LambdaQueryWrapper<BorrowRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BorrowRecord::getUserId, userId)
                .eq(BorrowRecord::getStatus, "0"); // 借阅中
        return (int) count(wrapper);
    }

    @Override
    public boolean checkBookAvailable(Long bookId) {
        Book book = bookService.getById(bookId);
        if (book == null) {
            return false;
        }
        // 检查状态和可借数量
        return "0".equals(book.getStatus()) && book.getAvailable() > 0;
    }
} 